import type { EditorProps, OnChange } from '@monaco-editor/react';
import { Editor as MonacoEditor } from '@monaco-editor/react';
import { Spin } from 'antd';
import { FC, useCallback, useContext, useRef, useState } from 'react';
import HeaderBar from './headerCom';
import { Button } from 'antd';
import { WrapContext } from './wrap';
import 'monaco-editor/esm/vs/basic-languages/css/css.contribution';
import 'monaco-editor/esm/vs/basic-languages/xml/xml.contribution';
import 'monaco-editor/esm/vs/basic-languages/javascript/javascript.contribution';

import EditorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker';
import TsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker';
import JsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker';
import CssWorker from 'monaco-editor/esm/vs/language/css/css.worker?worker';
import HtmlWorker from 'monaco-editor/esm/vs/language/html/html.worker?worker';
import { useInterval } from '@/hooks';
import { Masker } from './masker';
import { STORAGE_CODE, STORAGE_SUBMIT_HISTORY } from '@/utils';

// 定时保存
const autoSaveInterval = 5;

window.MonacoEnvironment = {
  getWorker(_: string, label: string) {
    if (label === 'typescript' || label === 'javascript') return new TsWorker();
    if (label === 'json') return new JsonWorker();
    if (label === 'css') return new CssWorker();
    if (label === 'html') return new HtmlWorker();
    return new EditorWorker();
  },
};
const CodeEditor: FC<EditorProps> = (props) => {
  const [theme] = useState('vs');
  const context = useContext(WrapContext);

  // sessionStorage中存储的代码
  const storageStr: string | null = sessionStorage.getItem(STORAGE_CODE);
  // sessionStorage中的数据结构
  let storage: CODE_STORAGE_TYPE | null;
  // 默认值
  let defaultValue = '';
  if (storageStr) {
    storage = JSON.parse(storageStr) as CODE_STORAGE_TYPE | null;
    // 如果存在缓存, 且缓存是本题的
    if (storage && storage.problem_id === context?.problem_id) {
      defaultValue = storage.code;
    }
  }
  const [value, setValue] = useState<string>(defaultValue);
  // 用于记录自动保存的内容
  const autoSavedValue = useRef('');
  // 用于记录提交了的内容
  const submitedValue = useRef('');
  // 定时器自动保存/同步
  const seconds = useInterval(autoSaveInterval);
  // 防止在到时间的那一秒内反复渲染反复提交
  const isOk = useRef<boolean>();

  // code和test阶段都可以进行自动保存
  if (context && ['test', 'code'].includes(context.stage)) {
    // 时间到自动保存
    if (seconds === autoSaveInterval) {
      if (isOk.current) {
        isOk.current = false;
        if (
          value &&
          value !== autoSavedValue.current &&
          value !== submitedValue.current
        ) {
          autoSavedValue.current = value;
          if (context.problem_id) {
            // 存储对象
            const storage: CODE_STORAGE_TYPE = {
              problem_id: context.problem_id,
              code: value,
            };
            // 存入缓存
            sessionStorage.setItem(
              STORAGE_CODE,
              JSON.stringify(storage as CODE_STORAGE_TYPE),
            );
          }
          context?.sendMsg({ topic: 'context', data: { code: value } });
        }
      }
    } else {
      isOk.current = true;
    }
  }

  // 输入
  const handleChange = useCallback<OnChange>((data) => {
    if (data !== undefined) {
      setValue(data);
    } else {
      setValue('');
    }
  }, []);

  // 提交
  const submit = useCallback(() => {
    if (
      context?.problem_id !== undefined &&
      value !== undefined &&
      context.questionDetail?.languages !== undefined
    ) {
      console.log(
        context?.problem_id,
        value,
        context.questionDetail?.languages,
        'submit-info',
      );
      submitedValue.current = value;
      context?.sendMsg({
        topic: 'test',
        data: {
          problem_id: context.questionDetail.id,
          code: value,
          language: 'C++',
        },
      });
    }
  }, [context, value]);

  // 测试结果
  const [result, setResult] = useState<RESULTTYPE | null>(null);
  // 提交历史
  const storageHistoryStr = sessionStorage.getItem(STORAGE_SUBMIT_HISTORY);
  // 历史提交记录存储格式
  let storageHistory: TEST_HISTORY | null = null;
  // 默认历史提交记录
  let defaultHistory: TEST_HISTORY['data'] | undefined;
  // 如果存在
  if (storageHistoryStr) {
    storageHistory = JSON.parse(storageHistoryStr);
    // 如果problem_id相同
    if (storageHistory?.problem_id === context?.problem_id) {
      defaultHistory = storageHistory?.data;
    } else {
      // 如果不是本题的缓存信息, 则删除该缓存
      sessionStorage.removeItem(STORAGE_SUBMIT_HISTORY);
    }
  }
  // 提交的最新历史记录(前端缓存)
  const [history, setHistory] = useState<TEST_HISTORY['data'] | undefined>(
    defaultHistory,
  );
  const timeRef = useRef<NodeJS.Timeout>();
  // 接收来自websocket的消息
  const receiveWS = useCallback(
    (msg: unknown) => {
      const _msg = msg as unknown as RECE_MSG_TYPE;
      // 聊天消息处理
      if (_msg.topic === 'test') {
        // 显示成绩
        setResult(_msg.data);
        // 如果返回的是测试结果
        if (_msg.data.pass !== undefined && _msg.data.total !== undefined) {
          // 存在测试用例结果
          if (_msg.data.total > 0 && context?.problem_id) {
            setHistory(_msg.data);
            // 缓存到sessionStorage中
            sessionStorage.setItem(
              STORAGE_SUBMIT_HISTORY,
              JSON.stringify({
                problem_id: context.problem_id,
                data: _msg.data,
              } as TEST_HISTORY),
            );
          }
          clearTimeout(timeRef.current);
          // 则显示5秒后隐藏提示
          timeRef.current = setTimeout(() => {
            setResult(null);
          }, 5000);
        }
        // 解题阶段更新
      } else if (_msg.topic === 'context') {
        if (_msg.data.stage !== undefined) {
          context?.setStage(_msg.data.stage);
        }
      }
    },
    [context],
  );
  // 监听websocket
  context?.ws?.addEvent(receiveWS);

  return (
    <>
      {context &&
        ['code', 'test', 'success', 'fail'].includes(context.stage) && (
          <div className='relative mt-[16px] flex flex-col rounded-large grow shrink basis-1 overflow-hidden border-[#DADADA] rounded-[8px]'>
            <HeaderBar
              title='编辑器'
              path={
                new URL('@/assets/imgs/icon-code.png', import.meta.url).href
              }
            />
            {/* 编码/测试阶段 */}
            {
              <>
                <div className='bg-white grow shrink overflow-hidden'>
                  <MonacoEditor
                    loading={<Spin />}
                    language='c'
                    options={{
                      readOnly: ['success', 'fail'].includes(context.stage),
                    }}
                    theme={theme}
                    value={value}
                    {...props}
                    onChange={handleChange}
                  />
                </div>
                <div className='flex items-center bg-white pr-[16px] pb-[16px] text-right border-t pt-[15px]'>
                  {history?.total && history.total > 0 && (
                    // 显示提交的记录
                    <div className='text-[14px] pl-[22px]'>
                      <span className='text-[#333333]'>
                        最近一次提交的代码：
                      </span>{' '}
                      <span className='text-[#666]'>
                        通过了{history?.pass}/{history?.total}
                        个测试用例
                      </span>
                    </div>
                  )}
                  {['code', 'test'].includes(context.stage) && (
                    <Button
                      className='ml-[auto]'
                      type='primary'
                      disabled={!value || submitedValue.current === value}
                      onClick={submit}>
                      提交
                    </Button>
                  )}
                </div>
              </>
            }
            {/* 遮罩层 */}
            {result !== null && <Masker result={result} />}
          </div>
        )}
    </>
  );
};

export default CodeEditor;
